#pragma once

#include<iostream>
#include<vector>
#include<queue>
#include<pthread.h>
#include"Log.hpp"
#include"Thread.hpp"
#include"LockGuard.hpp"
#include"Log.hpp"
using namespace ThreadModule;
const static int gdefaultthreadnum = 5;

template<typename T>
class ThreadPool
{
    private:
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void unlockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void ThreadSleep()
    {
        pthread_cond_wait(&_code,&_mutex);
    }
    void ThreadWakeup()
    {
        pthread_cond_signal(&_code);
    }
    void ThreadWakeupAll()
    {
        //等待的线程全部唤醒
        pthread_cond_broadcast(&_code);
    }
    ThreadPool(int threadnum = gdefaultthreadnum)
        :_threadnum(threadnum)
        ,_waitnum(0)
        ,_isrunning(false)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_code,nullptr);
        LOG(INFO,"ThreadPool Construct()");
    }
    void InitThreadPool()
    {
        //指向构建除所有的线程，并不启动
        for(int num = 0;num<_threadnum;num++)
        {
            std::string name = "thread-"+std::to_string(num+1);
            _threads.emplace_back(std::bind(&ThreadPool::HandlerTask,this,std::placeholders::_1),name);
          LOG(INFO,"init thread %s done\n",name.c_str());
        }
        _isrunning = true;
    }
    void Start()
    {
        for(auto &thread:_threads)
        {
            thread.Start();
        }
    }
    void HandlerTask(std::string name)
    {
        LOG(INFO,"%s is running...\n",name.c_str());
        while (true)
        {
            //加锁保证队列安全
          LockQueue();
            //判断队列是否有数据
            while(_task_queue.empty()&&_isrunning)
            {
                _waitnum++;
                ThreadSleep();
                _waitnum--;
            }
            //线程退出&&队列为空
            if(_task_queue.empty()&&!_isrunning)
            {
                //解锁
                unlockQueue();
                break;
            }
            //线程不退出，任务队列不为空/线程退出，任务队列不为空处理完任务然后退出
            //一定有任务，处理任务
            T t = _task_queue.front();
            _task_queue.pop();
            //处理完解锁
            unlockQueue();
            LOG(DEBUG,"%s get a task",name.c_str());
            //处理任务这个任务属于线程独占的任务
            t();
        }
        
    }
    ThreadPool<T> &operator=(const ThreadPool<T> &) =delete;//禁止赋值
    ThreadPool(const ThreadPool<T> &) = delete;//禁止拷贝；
    public:
    static ThreadPool<T> *gerInstance()
    {
        //只有第一次会创建对象，后续都是获取
        //双判断的方式，可以有效减少获取单列的加锁成本，而保证线程安全
        if(nullptr==_instance)//保证第二次之后，所有进程不用在家所，直接返回_instance单列对象
        {
            //加锁
            LockGuard lockguard(&_lock);
            if(nullptr == _instance)
            {
                _instance = new ThreadPool<T>();
                _instance->InitThreadPool();
                _instance->Start();
               LOG(DEBUG,"创建线程池单例\n");
                return _instance;
            }
        }
        LOG(DEBUG,"获取线程池单例\n");
        return _instance;
    }
    void Stop()
    {
        //锁定队列
        LockQueue();
        _isrunning = false;
        ThreadWakeupAll();//唤醒等待队列中的全部线程
        unlockQueue();//解锁队列

    }
    void Wait()
    {
        for(auto &thread :_threads)
        {
            thread.Join();
            LOG(INFO,"%s is quit...",thread.name().c_str());
        }
    }
    bool Enqueue (const T &t)
    {
        bool ret = false;
        //锁定队列
        LockQueue();
        if(_isrunning)
        {
            _task_queue.push(t);
            if(_waitnum>0)//等待数量
            {
                ThreadWakeup();//线程唤醒
            }
          LOG(DEBUG,"enqueue task success\n");
            ret = true;
        }
        //解锁队列
        unlockQueue();
        return ret;
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_code);

    }
    private:
    int _threadnum;
    std::vector<Thread> _threads;
    std::queue<T> _task_queue;
    pthread_mutex_t _mutex;
    pthread_cond_t _code;

    int _waitnum;
    int _isrunning;

    static ThreadPool<T> *_instance;
    static pthread_mutex_t _lock;

};
template<typename T>
ThreadPool<T> *ThreadPool<T>::_instance = nullptr;
template<typename T>
pthread_mutex_t ThreadPool<T>::_lock = PTHREAD_MUTEX_INITIALIZER;
